package cn.molu.jsoup.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 陌路
 * @apiNote 解析网站资源测试类
 * @date 2024/1/16 14:02
 * @tool Created by IntelliJ IDEA
 */
public class GetWebResourceTest {

    /**
     * 通过解析网页获取资源
     */
    public static void main(String[] args) {
        // 获取网页资源
        Document document = Jsoup.parse(HttpUtil.get("https://pic.sogou.com/pic/searchList.jsp?from=homeHotSearch&rcer=&spver=0&keyword=%E7%BE%8E%E5%A5%B3%E5%A3%81%E7%BA%B8#top=1395.199951171875&more=true", 15000));
        // 只获取<body>标签中的元素
        Element body = document.body();
        // 使用css选择器提取所有资源，得到列表数据
        Elements aElements = Optional.of(body.select("div#result"))
                .orElseGet(Elements::new).select("div.similar div.similar-item a.single-box");
        // 进一步解析，获取资源链接和标题，将资源收集成集合中
        Set<JSONObject> result = aElements.stream().map(tag -> {
            JSONObject resource = new JSONObject();
            String title = tag.select("div.img-info h4.info-title").text();
            String src = tag.select("div.img-height img").attr("src");
            return resource.set("title", title).set("src", src);
        }).filter(ObjUtil::isNotEmpty).collect(Collectors.toSet());
        // 打印数据集
        System.out.println(result);
        System.out.println("共获取到：" + result.size() + "条数据");
    }

    /**
     * 通过API接口获取资源
     */
    public static void main1(String[] args) {
        // 查询接口
        String postUrl = "https://pic.sogou.com/napi/wap/searchlist";
        // 查询参数
        String params = """
                {
                    "initQuery": "美女手机壁纸",
                    "queryFrom": "wap",
                    "from": "homeHotSearch",
                    "rcer": "",
                    "spver": "0",
                    "keyword": "美女壁纸",
                    "start": 48,
                    "reqType": "client",
                    "reqFrom": "wap_result",
                    "prevIsRedis": "n",
                    "qua": "",
                    "headers": {},
                    "pagetype": 0,
                    "amsParams": []
                }
                """;
        // 发起post请求，得到上图所述的结果数据
        String json = HttpUtil.post(postUrl, params, 15000);
        // 解析结果数据，拿到最终的资源节点
        JSONArray jsonArray = JSONUtil.parseObj(json).getJSONObject("data").getJSONObject("picResult").getJSONArray("items");
        // 进一步解析提取所需要的资源数据，排除不需要的数据，将资源收集成集合中
        Set<JSONObject> result = jsonArray.stream().map(item -> {
            JSONObject resource = new JSONObject();
            if (item instanceof JSONObject jsonObject) {
                String title = jsonObject.getStr("title"); // 标题
                String picUrl = jsonObject.getStr("picUrl"); // 图片链接
                String thumbUrl = jsonObject.getStr("thumbUrl"); // 缩略图链接
                String oriPicUrl = jsonObject.getStr("oriPicUrl"); // 原图链接
                String locImageLink = jsonObject.getStr("locImageLink"); // 原图链接
                return resource.set("title", title).set("picUrl", picUrl)
                        .set("thumbUrl", thumbUrl).set("oriPicUrl", oriPicUrl)
                        .set("locImageLink", locImageLink);
            }
            return null;
        }).filter(ObjUtil::isNotEmpty).collect(Collectors.toSet());
        // 打印数据集
        System.out.println(result);
        System.out.println("共获取到：" + result.size() + "条数据");
    }

    /**
     * 通过js获取数据资源
     */
    public static void main2(String[] args) {
        // 请求资源地址得到页面数据
        Document document = Jsoup.parse(HttpUtil.get("https://pic.sogou.com/pic/searchList.jsp?from=homeHotSearch&rcer=&spver=0&tagQSign=%E9%AB%98%E6%B8%85,3636d5ad&showMode=0&routeName=searchlist&keyword=美女", 15000));
        String variableName = "window.__INITIAL_STATE__";
        // 解析得到所有的<script>
        Elements scriptTags = document.getElementsByTag("script");
        // 过滤得到包含'__INITIAL_STATE__'的<script>
        List<String> collects = scriptTags.stream().map(Element::data)
                .filter(data -> data.contains(variableName))
                .filter(StrUtil::isNotEmpty)
                .toList();
        String scriptData = CollectionUtil.isEmpty(collects) ? "" : collects.get(0);
        // 截取js中'__INITIAL_STATE__'变量内容
        int startIndex = scriptData.indexOf("{");
        int endIndex = scriptData.lastIndexOf("}");
        // 得到js中'__INITIAL_STATE__'的json数据
        String jsonData = scriptData.substring(startIndex, endIndex + 1);
        // 将JS数据转为Java的JSON对象
        JSONObject jsonObject = JSONUtil.parseObj(jsonData);
        jsonObject = jsonObject.getJSONObject("searchlist");
        jsonObject = jsonObject.getJSONObject("groupFixedResult");
        JSONArray groupPicArray = jsonObject.getJSONArray("groupPic");
        Set<Map<String, String>> list = new HashSet<>();
        // 从JSON对象中提取资源数据
        getSource(groupPicArray, list);
        // 打印数据集
        System.out.println(list);
        System.out.println("共获取到：" + list.size() + "条数据");
    }

    /**
     * 解析资源，获取资源数据
     *
     * @param jsonArray 资源数据集
     * @param list      结果数据集
     */
    private static void getSource(JSONArray jsonArray, Set<Map<String, String>> list) {
        for (Object object : jsonArray) {
            if (object instanceof JSONArray item) {
                getSource(item, list);
            }
            if (object instanceof JSONObject item) {
                var map = new HashMap<String, String>();
                map.put("thumbUrl", item.getStr("thumbUrl"));
                map.put("title", item.getStr("title"));
                map.put("pageUrl", item.getStr("pageUrl"));
                map.put("picUrl", item.getStr("picUrl"));
                list.add(map);
            }
        }
    }
}
